
// Copyright (C) 2009-2011 Luca Piccioni
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;

namespace Derm.Render
{
	/// <summary>
	/// Transformation context.
	/// </summary>
	/// <remarks>
	/// <para>
	/// Often, when dealing with matrices, it is necessary to compute the matrix inverse. Inverse matrix is an heavy computation,
	/// and it is preferable to cache inverse matrix result.
	/// </para>
	/// <para>
	/// This class allow to cache the inverse matrix of any transformation matrix. The inverse matrix is computed only if it requested; if
	/// the application code doesn't requires the inverse matrix, it won't be computed.
	/// </para>
	/// </remarks>
	class TransformContext : ICloneable
	{
		#region Constructors

		/// <summary>
		/// Default constructor.
		/// </summary>
		/// <remarks>
		/// Transform matrices are initially set to null.
		/// </remarks>
		public TransformContext()
		{
			
		}

		/// <summary>
		/// Constructor with transform matrix.
		/// </summary>
		/// <param name="trans">
		/// A <see cref="Matrix4x4"/> that specifies the initial transformation matrix.
		/// </param>
		/// <remarks>
		/// Transform matrix is initially set to <paramref name="trans"/>.
		/// </remarks>
		public TransformContext(Matrix4x4 trans)
		{
			if (trans == null)
				throw new ArgumentNullException("trans");

			// Store transformation matrix
			TransformMatrix = trans;
		}

		#endregion

		#region Transform Matrix

		/// <summary>
		/// Transform matrix.
		/// </summary>
		public Matrix4x4 TransformMatrix
		{
			get { return (mMatrix); }
			set {
				// Store transform matrix
				mMatrix = value;
				// Reset inverse matrix
				mInverseMatrix = null;
			}
		}

		/// <summary>
		/// Projection matrix.
		/// </summary>
		private Matrix4x4 mMatrix;

		#endregion

		#region Inverse Transform Matrix

		/// <summary>
		/// Inverse transform matrix.
		/// </summary>
		public Matrix4x4 InverseTransformMatrix
		{
			get {
				// Compute inverse matrix if not yet done
				if ((mInverseMatrix == null) && (mMatrix != null))
					mInverseMatrix = mMatrix.GetInverseMatrix();

				return (mInverseMatrix);
			}
		}

		/// <summary>
		/// Model matrix.
		/// </summary>
		private Matrix4x4 mInverseMatrix;

		#endregion

		#region ICloneable Implementation

		/// <summary>
		/// Clone this TransformContext.
		/// </summary>
		/// <returns>
		/// It returns a deep copy of this TransformContext.
		/// </returns>
		public virtual object Clone()
		{
			TransformContext clone = new TransformContext();

			// Clone tranform matrix
			if (mMatrix != null)
				clone.mMatrix = (Matrix4x4)mMatrix.Clone();
			// Clone its inverse if already cached
			if (mInverseMatrix != null)
				clone.mInverseMatrix = (Matrix4x4)mInverseMatrix.Clone();

			return (clone);
		}

		#endregion
	}
}
